package com.lie.prepare.basic;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

import static com.lie.prepare.util.Print.*;

/**
 * Created by lie on 2018/4/11.
 * 4种引用
 * 注意对比{@link #weak()}和{@link #weak2()}的区别，注意引用链
 */
public class ReferenceDemo {

    public static void main(String[] args){

//        soft1();
//        soft2();

//        weak();
        weak2();
//        phantom();
    }




    private static void makeOOM() {
        String str="hello";
        try{
            for(int x=0;x<Integer.MAX_VALUE;x++){
                str+=str+x;
                str.intern();
            }
        }catch(Throwable e){
            print("哎哟，内存炸了");
        }
    }



    /**
     * 充足，不回收
     */
    private static void soft1() {
        //不足时回收，充足时不回收
        Object o = new Object();
        SoftReference<Object> sr = new SoftReference<Object>(o);

        o=null;//断开连接
        System.gc();

        Object get = sr.get();
        print("o = " + get);//o = java.lang.Object@60e53b93
        //可以看到，并没有回收
    }

    /**
     * 不充足，回收
     */
    private static void soft2() {
        Object o = new Object();
        SoftReference<Object> sr = new SoftReference<Object>(o);

        o=null;
        makeOOM();

        System.gc();

        Object get = sr.get();
        //可以看到，回收了
        print("o = " + get);//o = null
    }


    //不管内存是否足够，只要触发GC，就回收
    private static void weak() {
        Object obj = new Object();
        WeakReference<Object> wr = new WeakReference<Object>(obj);

//        makeOOM();
        //因为obj是强引用 ，所以假如不为null的话，WeakReference关联的数据也在一条强引用链上的是不会被回收的
        obj = null;
        print("触发gc前 o = "+ wr.get());//o = java.lang.Object@60e53b93
        System.gc();

        print("触发gc前 o = "+ wr.get());//o = null
    }

    private static void weak2() {
        WeakReference<Object> wr = new WeakReference<Object>(new Object());
        print("触发gc前 o = "+ wr.get());//o = java.lang.Object@60e53b93
        System.gc();
        print("触发gc前 o = "+ wr.get());//o = null
    }


    //永远取得不了的数据就叫做幽灵引用
    //要注意的是，虚引用必须和引用队列关联使用，
    // 当垃圾回收器准备回收一个对象时，如果发现它还有虚引用，
    // 就会把这个虚引用加入到与之 关联的引用队列中。
    // 程序可以通过判断引用队列中是否已经加入了虚引用，
    // 来了解被引用的对象是否将要被垃圾回收。
    // 如果程序发现某个虚引用已经被加入到引用队列，
    // 那么就可以在所引用的对象的内存被回收之前采取必要的行动。
    private static void phantom() {
        Object obj=new Object();
        ReferenceQueue<Object> queue=new ReferenceQueue<Object>();
        PhantomReference<Object> ref=new PhantomReference<Object>(obj,queue);
        System.gc();
        //所有保存在幽灵引用类型中的数据都不会真正的保留。
        System.out.println(ref.get());//null
        System.out.println(queue.poll());//null
        //总之，幽灵引用是用来做某种标记的
    }
}
